import { Component, v3, Vec3, _decorator } from 'cc';
import { Loger } from '../../loger/Loger';
import { AStarLogic } from './AStarLogic';

export enum AStarNodeState {
    Free = 0,
    Move = 1,
}
const { ccclass, menu, property } = _decorator;
@ccclass
export class AStarNode extends Component{
    protected _speed: number;
    protected _curIdx: number;
    protected _posList: Vec3[];
    protected _curDir: Vec3;
    @property({ type: AStarLogic, tooltip: "算法逻辑" })
    protected _aStarLogic: AStarLogic = null;


    public state: AStarNodeState;
    public position: Vec3;
    public get posList(): Vec3[] { return this._posList; }
    public get curIdx(): number { return this._curIdx; }

    public init(pos: Vec3) {
        this.state = AStarNodeState.Free;
        this.position = pos;
    }


    public setPosition(x:number,y:number){
        this.position = v3(x,y);
        this.changeState(AStarNodeState.Free);
    }

    public isMove(): boolean {
        return this.state == AStarNodeState.Move;
    }

    /**计算路线 */
    public findPath(targetPos: Vec3): Vec3[] {
        let posList = this._aStarLogic.findPathPosList(this.position, targetPos);
        if (!posList) {
            return null;
        }
        this._posList = posList;
        this._curIdx = 0;
        return this._posList;
    }

    /**返回当前寻路距离 */
    public calcDis(): number {
        if (!this._posList) {
            return 0;
        }
        let dis = 0;
        for (let i = 0; i < this._posList.length; i++) {
            //计算距离
            if (i > 0) {
                dis += this._posList[i].subtract(this._posList[i - 1]).length();
            }
        }
        return dis;
    }

    /**计算当前移动方向 */
    private calcCurDir() {
        this._curDir = this._posList[this._curIdx].subtract(this.position).normalize();
    }

    /**根据比例和移动轨迹计算位置 */
    public calcPosWithRate(rate: number): Vec3 {
        let moveDis = this.calcDis() * rate;
        let pos = null;
        let dis = 0;
        let dir: Vec3 = null;
        let oneDis = 0;
        for (let i = 0; i < this._posList.length; i++) {
            //计算距离
            if (i > 0) {
                dir = this._posList[i].subtract(this._posList[i - 1])
                oneDis = dir.length();
                dis += oneDis;
                if (dis > moveDis) {
                    this._curIdx = i;
                    this.position = this._posList[i - 1].add(dir.normalize().multiplyScalar(oneDis - (dis - moveDis)))
                    this.calcCurDir();
                    return this.position;
                }
            }
        }
        return this.position;
    }
    /**停止移动 */
    public stopMove() {
        this.changeState(AStarNodeState.Free);
    }

    /**根据时间移动 必须先findPath 找到路线再执行 */
    public moveToTargetWithTime(time: number) {
        let dis = this.calcDis();
        this._speed = dis / time;
        this._beginMove();
    }
    /**根据速度移动 必须先findPath 找到路线再执行 */
    public moveToTargetWithSpeed(speed: number) {
        this._speed = speed;
        this._beginMove();
    }

    /**开始移动 */
    private _beginMove() {
        this._curIdx = 0;
        if (!this._posList || !this._posList[this._curIdx]) {
            Loger.log("have no path")
            return
        }
        this.calcCurDir();
        this.changeState(AStarNodeState.Move);
    }

    public changeState(state: AStarNodeState) {
        Loger.log("AStarNode change state ",state);
        if (this.state == state) {
            return;
        }
        this.state = state;

    }

    protected onMove(completedCount: number, totalCount: number) {
    }
    protected onDone() {
    }
    protected onMoveTick(dt: number, x: number, y: number) {
    }

    tick(dt) {
        switch (this.state) {
            case AStarNodeState.Move: {
                this.position = this.position.add(this._curDir.multiplyScalar(this._speed * dt))
                // let dis = this.position.sub(this._posList[this._curIdx]).mag();
                // Loger.log("dis====>>>",dis,this._curIdx,dt);
                if (this.position.subtract(this._posList[this._curIdx]).length() <= this._speed * dt + 2) {
                    this.position = this._posList[this._curIdx];

                    this._curIdx++;
                    this.onMove(this._curIdx, this._posList.length);
                    if (this._curIdx >= this._posList.length) {
                        this.changeState(AStarNodeState.Free);

                        this.onDone();
                    } else {
                        this.calcCurDir();
                    }
                }
                this.onMoveTick(dt, this.position.x, this.position.y);
            }
                break;

        }
    }
}